package com.luhuiguo.gwt.security.server;

import org.gwtwidgets.server.spring.GWTRPCServiceExporter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;

import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.UnexpectedException;

/**
 * 
 * @author LuHuiguo
 * @version $Id: GWTRPCSecuredServiceExporter.java 3 2009-12-14 06:18:57Z luhuiguo $
 */
public class GWTRPCSecuredServiceExporter extends GWTRPCServiceExporter {

    private static final long serialVersionUID = 6166548209648395004L;

    @Override
    public String processCall(String payload) throws SerializationException {
        String response = null;

        final RPCRequest rpcRequest = RPC.decodeRequest(payload, null, this);
        try {
            response = super.processCall(payload);
        } catch (final Throwable e) { // Security Exceptions (preciousException
            // here) are wrapped into an
            // UnexpectedException (cause1), which is
            // wrapped into a RuntimeException (e)...
            final Throwable cause1 = e.getCause();
            if (cause1 != null && cause1 instanceof UnexpectedException) {
                final Throwable preciousException = cause1.getCause();
                if (preciousException != null
                        && (preciousException instanceof AccessDeniedException || preciousException instanceof AuthenticationException)) {
                    String failurePayload = null;
                    try {
                        failurePayload = RPC.encodeResponseForFailure(rpcRequest.getMethod(), SecurityExceptionFactory
                                .get((RuntimeException) preciousException));
                    } catch (final UnexpectedException ue) {
                        logger
                                .error("You may have forgotten to add a 'throws GWTSecurityException' declaration to your service interface.");
                        throw ue;
                    }
                    return failurePayload;
                }
            }
            handleOtherException(e);
        }
        return response;

    }

    protected void handleOtherException(final Throwable e) throws SerializationException {
        if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
        } else if (e instanceof SerializationException) {
            throw (SerializationException) e;
        } else {
            throw new SerializationException(e);
        }
    }
}
